import { Extension } from '@tiptap/react';

export const LineHeightExtension = Extension.create({
  name: 'lineHeight',
  addOptions() {
    return {
      types: ['paragraph', 'heading'],
      defaultLineHeight: 'normal',
    };
  },
  addGlobalAttributes() {
    return [
      {
        types: this.options.types,
        attributes: {
          lineHeight: {
            default: this.options.defaultLineHeight,
            parseHTML: (element) => element.style.lineHeight,
            renderHTML: (attributes) => {
              if (!attributes.lineHeight) {
                return {};
              }
              return { style: `line-height:${attributes.lineHeight}` };
            },
          },
        },
      },
    ];
  },
  addCommands() {
    return {
      setLineHeight:
        (lineHeight) =>
        ({ tr, state, dispatch }) => {
          const { selection } = state;
          // 更新事务(transaction)的选择状态
          tr = tr.setSelection(selection);

          // 获取选择范围的起始和结束位置
          const { from, to } = selection;
          // 遍历选择范围内的所有节点
          state.doc.nodesBetween(from, to, (node, pos) => {
            // 检查节点类型是否在可设置行高的类型列表中
            if (this.options.types.includes(node.type.name)) {
              // 更新节点属性，设置新的行高值
              tr = tr.setNodeMarkup(pos, undefined, {
                ...node.attrs, // 保留原有属性
                lineHeight, // 添加/更新行高属性
              });
            }
          });

          // 如果有dispatch函数，则提交事务变更
          if (dispatch) dispatch(tr);
          // 返回true表示命令执行成功
          return true;
        },
      unsetLineHeight:
        () =>
        ({ tr, state, dispatch }) => {
          const { selection } = state;
          tr = tr.setSelection(selection);

          const { from, to } = selection;
          state.doc.nodesBetween(from, to, (node, pos) => {
            if (this.options.types.includes(node.type.name)) {
              tr = tr.setNodeMarkup(pos, undefined, {
                ...node.attrs,
                lineHeight: this.options.defaultLineHeight,
              });
            }
          });

          if (dispatch) dispatch(tr);
          return true;
        },
    };
  },
});
